#include "MainWindow.h"
#include "ui_MainWindow.h"
#include <QtGui>
#include <QApplication>
#include <QSettings>
#include <QTextCursor>

#include "Main/AboutDialog.h"
#include "CodeEditor/Syntax/SyntaxHighlighterFactory.h"
#include "Config/ConfigDialog.h"
#include "Config/GeneralSettings.h"

#ifdef Q_OS_WIN32
#include <windows.h>
#endif

MainWindow::MainWindow(QWidget* parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    createTrayIcon();
    setupStatusBarIndicators();
    connectSignalsAndSlots();
    enableInvisibleActions();
    initStates();
    loadStates();
    qApp->installTranslator(&_translator);
    loadSettings();
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::changeEvent(QEvent* event)
{
    QMainWindow::changeEvent(event);
    switch (event->type()) {
    case QEvent::LanguageChange:
        ui->retranslateUi(this);
        setFileName(_fileName);
        break;
    // Minimize to tray
    case QEvent::WindowStateChange:
        if (isMinimized()) {
            /* Call the hide slot after 200ms to process other events
             * @see http://www.qtcentre.org/forum/archive/index.php/t-6593.html
             */
            qApp->processEvents();
            QTimer::singleShot(200, this, SLOT(hide()));
            event->ignore();
        }
        break;
    default:
        break;
    }
}

/**
 * @override
 * Close to tray.
 */
void MainWindow::closeEvent(QCloseEvent* event)
{
    quit();
}

/**
 * @public, @override
 * Updates tray icon context menu states.
 */
void MainWindow::setVisible(bool visible)
{
    ui->actMinimize->setEnabled(visible);
    ui->actMaximize->setEnabled(!isMaximized());
    ui->actRestore->setEnabled(isMaximized() || !visible);
    QMainWindow::setVisible(visible);
}

/**
 * @override, @protected
 * On pressing Escape:
 *   1, Closes find/replace panel if shown.
 *   2, Otherwise, minimize to tray.
 */
void MainWindow::keyPressEvent(QKeyEvent* event)
{
    QMainWindow::keyPressEvent(event);
    if (event->key() == Qt::Key_Escape) {
        if (ui->pnlFindReplace->isVisible()) {
            ui->pnlFindReplace->setVisible(false);
        }
        else {
            hide();
        }
    }
}

/**
 * @private
 * Creates the system tray icon and its context menu.
 */
void MainWindow::createTrayIcon()
{
    _trayIconMenu = new QMenu(this);
    _trayIconMenu->addAction(ui->actNew);
    _trayIconMenu->addAction(ui->actOpen);
    _trayIconMenu->addAction(ui->actSave);
    _trayIconMenu->addAction(ui->actSaveAs);
    _trayIconMenu->addSeparator();
    _trayIconMenu->addAction(ui->actAbout);
    _trayIconMenu->addSeparator();
    _trayIconMenu->addAction(ui->actQuit);

    _trayIcon = new QSystemTrayIcon(QIcon(":/codepad"), this);
    _trayIcon->setContextMenu(_trayIconMenu);
    _trayIcon->setVisible(true);
    connect(_trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)),
            this, SLOT(trayIconActivated(QSystemTrayIcon::ActivationReason)));
}

void MainWindow::trayIconActivated(QSystemTrayIcon::ActivationReason reason)
{
    switch (reason) {
    case QSystemTrayIcon::Trigger:
        if (!isVisible()) {
            if (isMaximized())
                showMaximized();
            else
                showNormal();
            activateWindow();
        } else {
            hide();
        }
        break;
    default: break;
    }
}

void MainWindow::setupStatusBarIndicators()
{
    _sbiSyntax = new QToolButton;
    _sbiSyntax->setIconSize(QSize(16, 16));
    _sbiSyntax->setAutoRaise(false);
    _sbiSyntax->setPopupMode(QToolButton::InstantPopup);
    _sbiSyntax->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
    _sbiSyntax->setDefaultAction(ui->actSyntaxCpp);
    _sbiSyntax->addAction(ui->actSyntaxNone);
    _sbiSyntax->addAction(ui->actSyntaxCpp);
    _sbiSyntax->addAction(ui->actSyntaxPascal);
    _sbiSyntax->addAction(ui->actSyntaxSql);
    _sbiSyntax->addAction(ui->actSyntaxHtml);
    ui->statusBar->addPermanentWidget(_sbiSyntax);

//! [row-col indicator]
    _sbiColRow = new QToolButton;
    _sbiColRow->setIconSize(QSize(16, 16));
    _sbiColRow->setAutoRaise(false);
    _sbiColRow->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
    _sbiColRow->setDefaultAction(ui->actGotoLine);
    ui->statusBar->addPermanentWidget(_sbiColRow);
    emit codeEditCursorPositionChanged();
//! [row-col indicator]

//! [lock state indicator]
    _sbiLock = new QToolButton;
    _sbiLock->setIconSize(QSize(16, 16));
    _sbiLock->setAutoRaise(false);
    _sbiLock->setDefaultAction(ui->actLock);
    _sbiLock->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
    ui->statusBar->addPermanentWidget(_sbiLock);
//! [lock state indicator]

//! [zoom in/out indicator]
    _sbiZoomReset = new QToolButton;
    _sbiZoomReset->setIconSize(QSize(16, 16));
    _sbiZoomReset->setAutoRaise(false);
    _sbiZoomReset->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
    _sbiZoomReset->setDefaultAction(ui->actZoomReset);
    _sbiZoomReset->setText("100%");
    ui->statusBar->addPermanentWidget(_sbiZoomReset);

    _sbiZoomOut = new QToolButton;
    _sbiZoomOut->setIconSize(QSize(16, 16));
    _sbiZoomOut->setAutoRaise(false);
    _sbiZoomOut->setAutoRepeat(true);
    _sbiZoomOut->setDefaultAction(ui->actZoomOut);
    ui->statusBar->addPermanentWidget(_sbiZoomOut);

    _sbiZoomIn = new QToolButton;
    _sbiZoomIn->setIconSize(QSize(16, 16));
    _sbiZoomIn->setAutoRaise(false);
    _sbiZoomIn->setAutoRepeat(true);
    _sbiZoomIn->setDefaultAction(ui->actZoomIn);
    ui->statusBar->addPermanentWidget(_sbiZoomIn);
//! [zoom in/out indicator]
}

void MainWindow::connectSignalsAndSlots()
{
//! [action event handlers]
//! [file]
    connect(ui->actNew, SIGNAL(triggered()), this, SLOT(newFile()));
    connect(ui->actOpen, SIGNAL(triggered()), this, SLOT(openFile()));
    connect(ui->actSave, SIGNAL(triggered()), this, SLOT(saveFile()));
    connect(ui->actSaveAs, SIGNAL(triggered()), this, SLOT(saveFileAs()));
    connect(ui->actQuit, SIGNAL(triggered()), this, SLOT(quit()));
//! [file]
//! [zoom]
    connect(ui->actZoomIn, SIGNAL(triggered()), ui->codeEdit, SLOT(zoomIn()));
    connect(ui->actZoomOut, SIGNAL(triggered()), ui->codeEdit, SLOT(zoomOut()));
    connect(ui->actZoomReset, SIGNAL(triggered()), ui->codeEdit, SLOT(zoomReset()));
    connect(ui->codeEdit, SIGNAL(fontZoomChanged(int)), this, SLOT(fontZoomChanged(int)));
//! [zoom]
//! [find]
    connect(ui->actFind, SIGNAL(triggered()), this, SLOT(find()));
    connect(ui->actFindNext, SIGNAL(triggered()), this, SLOT(doFind()));
    connect(ui->edtTextToFind, SIGNAL(returnPressed()), this, SLOT(doFind()));
    connect(ui->chkUseRegExp, SIGNAL(toggled(bool)), this, SLOT(chkUseRegExpToggled(bool)));
    connect(ui->btnCloseFind, SIGNAL(clicked()), ui->pnlFindReplace, SLOT(hide()));
//! [find]
//! [replace]
    connect(ui->actReplace, SIGNAL(triggered()), this, SLOT(replace()));
    connect(ui->edtTextToReplace, SIGNAL(returnPressed()), this, SLOT(doReplace()));
    connect(ui->btnReplaceAll, SIGNAL(clicked()), this, SLOT(doReplaceAll()));
//! [replace]
    connect(ui->actCascade, SIGNAL(triggered(bool)), this, SLOT(cascadeWindow(bool)));
    connect(ui->actConfig, SIGNAL(triggered()), this, SLOT(config()));
    connect(ui->actUndo, SIGNAL(triggered()), ui->codeEdit, SLOT(undo()));
    connect(ui->actRedo, SIGNAL(triggered()), ui->codeEdit, SLOT(redo()));
    connect(ui->actGotoLine, SIGNAL(triggered()), this, SLOT(gotoLine()));
    connect(ui->actToggleTopMost, SIGNAL(triggered(bool)), this, SLOT(toggleTopMost(bool)));
    connect(ui->actToggleStatusbar, SIGNAL(triggered()), this, SLOT(toggleStatusbar()));
    connect(ui->actToggleToolbar, SIGNAL(triggered()), this, SLOT(toggleToolbar()));
    connect(ui->actToggleFullScreen, SIGNAL(triggered()), this, SLOT(toggleFullScreen()));
    connect(ui->actLock, SIGNAL(triggered(bool)), this, SLOT(lockFile(bool)));
    connect(ui->actSyntaxNone, SIGNAL(triggered()), this, SLOT(setSyntax()));
    connect(ui->actSyntaxCpp, SIGNAL(triggered()), this, SLOT(setSyntax()));
    connect(ui->actSyntaxPascal, SIGNAL(triggered()), this, SLOT(setSyntax()));
    connect(ui->actSyntaxSql, SIGNAL(triggered()), this, SLOT(setSyntax()));
    connect(ui->actSyntaxHtml, SIGNAL(triggered()), this, SLOT(setSyntax()));
    connect(ui->actMinimize, SIGNAL(triggered()), this, SLOT(hide()));
    connect(ui->actMaximize, SIGNAL(triggered()), this, SLOT(showMaximized()));
    connect(ui->actRestore, SIGNAL(triggered()), this, SLOT(showNormal()));
    connect(ui->actAbout, SIGNAL(triggered()), this, SLOT(about()));
//! [action event handlers]

//! [defered state update]
    connect(ui->codeEdit, SIGNAL(cursorPositionChanged()),
            this, SLOT(codeEditCursorPositionChanged()));
    connect(ui->codeEdit, SIGNAL(fileDropped(const QString&)),
            this, SLOT(codeEditFileDropped(const QString&)));
    connect(ui->codeEdit->document(), SIGNAL(modificationChanged(bool)),
            ui->actSave, SLOT(setEnabled(bool)));
    connect(ui->codeEdit->document(), SIGNAL(undoAvailable(bool)),
            ui->actUndo, SLOT(setEnabled(bool)));
    connect(ui->codeEdit->document(), SIGNAL(redoAvailable(bool)),
            ui->actRedo, SLOT(setEnabled(bool)));
//! [defered state update]
}

/**
 * Qt4 treats invisible actions as if they are disabled, i.e. not triggered.
 * Adding the actions to mainWindow solves this problem.
 */
void MainWindow::enableInvisibleActions()
{
    addAction(ui->actOpen);
    addAction(ui->actNew);
    addAction(ui->actSave);
    addAction(ui->actSaveAs);
    addAction(ui->actQuit);
    addAction(ui->actZoomIn);
    addAction(ui->actZoomOut);
    addAction(ui->actZoomReset);
    addAction(ui->actFind);
    addAction(ui->actFindNext);
    addAction(ui->actReplace);
    addAction(ui->actToggleTopMost);
    addAction(ui->actToggleToolbar);
    addAction(ui->actToggleStatusbar);
    addAction(ui->actToggleFullScreen);
    addAction(ui->actCascade);
    addAction(ui->actConfig);
    addAction(ui->actUndo);
    addAction(ui->actRedo);
    addAction(ui->actSyntaxNone);
    addAction(ui->actSyntaxCpp);
    addAction(ui->actSyntaxPascal);
    addAction(ui->actSyntaxSql);
    addAction(ui->actSyntaxHtml);
    addAction(ui->actLock);
    addAction(ui->actGotoLine);
    addAction(ui->actAbout);
}

/**
 * Initial action states.
 */
void MainWindow::initStates()
{
    setWindowIcon(QIcon(":/codepad"));

    ui->actSave->setEnabled(ui->codeEdit->document()->isModified());
    ui->actUndo->setEnabled(ui->codeEdit->document()->isUndoAvailable());
    ui->actRedo->setEnabled(ui->codeEdit->document()->isRedoAvailable());
    ui->actToggleTopMost->trigger();
    ui->actToggleStatusbar->trigger();
    ui->actToggleToolbar->trigger();
    ui->pnlFindReplace->setVisible(false);

    ui->actSyntaxNone->setData(QVariant(SyntaxHighlighterFactory::info("none")));
    ui->actSyntaxCpp->setData(QVariant(SyntaxHighlighterFactory::info("cpp")));
    ui->actSyntaxPascal->setData(QVariant(SyntaxHighlighterFactory::info("pas")));
    ui->actSyntaxSql->setData(QVariant(SyntaxHighlighterFactory::info("sql")));
    ui->actSyntaxHtml->setData(QVariant(SyntaxHighlighterFactory::info("htm")));
    ui->actSyntaxCpp->trigger();
}

/**
 * @private
 * Updates the associated _fileName and window title.
 */
void MainWindow::setFileName(const QString& fileName)
{
    _fileName = fileName;
    setWindowTitle(QString("%1 - %2").arg(this->fileName()).arg(qApp->applicationName()));
}

QString MainWindow::fileName() const
{
    return _fileName.isEmpty() ? tr("[Noname]") : QFileInfo(_fileName).fileName();
}

/**
 * @private
 * Closes current file.
 * @returns  False if document modified and 'Cancel' button clicked.
 */
bool MainWindow::closeFile()
{
    bool isDirty = ui->codeEdit->document()->isModified();
    if (isDirty) {
        QMessageBox::StandardButton btnId = QMessageBox::question(
            this, qApp->applicationName(),
            QString(tr("Document \"%1\" changed, save?")).arg(fileName()),
            QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel,
            QMessageBox::Discard
        );
        if (btnId == QMessageBox::Save) {
            saveFile();
        }
        return btnId == QMessageBox::Save || btnId == QMessageBox::Discard;
    }
    return true;
}

/**
 * @private slot
 * Creates new document
 */
void MainWindow::newFile()
{
    if (closeFile()) {
        setFileName(QString());
        ui->codeEdit->clear();
        ui->codeEdit->document()->setModified(false);
        ui->actSave->setEnabled(false);
    }
}

/**
 * @private slot
 * Opens document from file.
 * @param fileName  A given file to be opened. Prompts user for a filename if "" given.
 */
void MainWindow::openFile(const QString& fileName)
{
    if (closeFile()) {
        QString fileName_ = fileName;
        if (fileName_.isNull()) {
            fileName_ = QFileDialog::getOpenFileName(this, tr("Open file"), "",
                SyntaxHighlighterFactory::fileFilter());
        }
        if (!fileName_.isEmpty()) {
            const QFileInfo fi(fileName_);
            ui->codeEdit->open(fileName_);
            setSyntax(fi.suffix());
            setFileName(fileName_);
        }
    }
}

/**
 * @private slot
 * Saves document to file.
 */
void MainWindow::saveFile()
{
    if (_fileName.isNull()) {
        saveFileAs();
    } else {
        ui->codeEdit->save(_fileName);
    }
}

/**
 * @private slot
 * Prompts for associated _fileName, or saves current file as another file.
 */
void MainWindow::saveFileAs()
{
    QString fileName = QFileDialog::getSaveFileName(this, tr("Save file as"), "",
        SyntaxHighlighterFactory::fileFilter());
    if (!fileName.isEmpty()) {
        setFileName(fileName);
        saveFile();
    }
}

/**
 * @private slot
 * Quits the application. Prompts for saving if modified.
 */
void MainWindow::quit()
{
    if (closeFile()) {
        saveStates();
        qApp->quit();
    }
}

/**
 * @private slot
 * (Re)Loads and applies settings.
 * There's no such thing as saveSettings() in MainWindow -
 * settings are saved in ConfigDialog.
 */
void MainWindow::loadSettings()
{
    QSettings settings;
    GeneralSettings generalSettings;
    generalSettings.fromSettings(&settings);

    QString languageFile = QString(":/i18n/%1").arg(generalSettings.language);
    _translator.load(languageFile);
    qApp->setStyle(generalSettings.style);
    qApp->setFont(generalSettings.font);

    ui->codeEdit->loadSettings();
}

/**
 * @private slot
 * Loads window states.
 */
void MainWindow::loadStates()
{
    QSettings settings;
    settings.beginGroup("MainWindow");
    QPoint windowPos = settings.value("pos", pos()).toPoint();
    move(windowPos);
    QSize windowSize = settings.value("size", size()).toSize();
    resize(windowSize);
    bool isToolbarVisible = settings.value("toolbar/visible", true).toBool();
    ui->toolBar->setVisible(isToolbarVisible);
    bool isStatusbarVisible = settings.value("statusbar/visible", true).toBool();
    ui->statusBar->setVisible(isStatusbarVisible);
    settings.endGroup();
}

/**
 * @private slot
 * Saves window states.
 */
void MainWindow::saveStates()
{
    QSettings settings;
    settings.beginGroup("MainWindow");
    showNormal(); // restore window before saving its states
    settings.setValue("pos", pos());
    settings.setValue("size", size());
    settings.setValue("toolbar/visible", ui->toolBar->isVisible());
    settings.setValue("statusbar/visible", ui->statusBar->isVisible());
    settings.endGroup();
}

/**
 * @private slot
 */
void MainWindow::fontZoomChanged(int fontZoom)
{
    _sbiZoomReset->setText(QString("%1%").arg(fontZoom));
}

/**
 * @private
 * Gets the find options from ui.
 */
QTextDocument::FindFlags MainWindow::findOptions()
{
    QTextDocument::FindFlags ret = 0;
    if (ui->chkMatchCase->isChecked())
        ret |= QTextDocument::FindCaseSensitively;
    // chkMatchWord can be disabled when chkUseRegExp checked
    if (ui->chkMatchWord->isEnabled() && ui->chkMatchWord->isChecked())
        ret |= QTextDocument::FindWholeWords;
    return ret;
}

/**
 * @private slot
 * actFind action trigger() handler. Shows the find panel.
 */
void MainWindow::find(bool showReplace)
{
    ui->pnlFindReplace->setVisible(true);
    ui->pnlReplace->setVisible(showReplace);

    QTextCursor cursor = ui->codeEdit->textCursor();
    if (!cursor.hasSelection()) {
        cursor.select(QTextCursor::WordUnderCursor);
    }
    ui->edtTextToFind->setText(cursor.selectedText());
    ui->edtTextToFind->setFocus();
    ui->edtTextToFind->selectAll();
}

/**
 * @private slot
 * Finds the text specified by ui->edtTextToFind->text() inside CodeEditor.
 */
void MainWindow::doFind()
{
    bool useRegExp = ui->chkUseRegExp->isChecked();
    QString text = ui->edtTextToFind->text();

    // first lookup
    QTextCursor textCursor;
    if (!useRegExp) {
        textCursor = ui->codeEdit->document()->find(text, ui->codeEdit->textCursor(), findOptions());
    } else {
        QRegExp rx(text);
        if (ui->chkMatchCase->isChecked())
            rx.setCaseSensitivity(Qt::CaseSensitive);
        textCursor = ui->codeEdit->document()->find(rx, ui->codeEdit->textCursor(), findOptions());
    }

    // wrap at end if not found
    if (!textCursor.isNull()) {
        ui->codeEdit->setTextCursor(textCursor);
    }
    else {
        // not found, put text cursor to the beginning and find one more time.
        if (!useRegExp) {
            textCursor = ui->codeEdit->document()->find(text, QTextCursor(), findOptions());
        } else {
            QRegExp rx(text);
            if (ui->chkMatchCase->isChecked())
                rx.setCaseSensitivity(Qt::CaseSensitive);
            textCursor = ui->codeEdit->document()->find(rx, QTextCursor(), findOptions());
        }
        if (!textCursor.isNull())
            ui->codeEdit->setTextCursor(textCursor);
        else {
            // not found, clear possible previous selection
            textCursor = ui->codeEdit->textCursor();
            textCursor.clearSelection();
            ui->codeEdit->setTextCursor(textCursor);
        }
    }
}

/**
 * @private slot
 * `MatchWord` option should be disabled if `UseRegExp` option is checked.
 */
void MainWindow::chkUseRegExpToggled(bool checked)
{
    ui->chkMatchWord->setEnabled(!checked);
}

/**
 * @private slot
 * actReplace action trigger() handler. Shows the replace panel.
 */
void MainWindow::replace()
{
    find(true);
}

/**
 * @private slot
 * Replaces the \a textToReplace inside CodeEditor.
 */
void MainWindow::doReplace()
{
    QString textToFind = ui->edtTextToFind->text();
    QString textToReplace = ui->edtTextToReplace->text();
    // todo
}

/**
 * @private slot
 * Replaces all occurrences.
 */
void MainWindow::doReplaceAll()
{
    QString textToFind = ui->edtTextToFind->text();
    QString textToReplace = ui->edtTextToReplace->text();
    // todo
}

/**
 * @private slot
 * Makes MainWindow take least screen space. (Only the title bar will be shown)
 */
void MainWindow::cascadeWindow(bool)
{
    // todo
}

/**
 * @private slot
 * Prompts for application configurations.
 */
void MainWindow::config()
{
    ConfigDialog dlgConfig(this);
    if (dlgConfig.exec() == QDialog::Accepted) {
        loadSettings();
    }
}

/**
 * @private slot
 * Lock current document (file) for editing
 */
void MainWindow::lockFile(bool lock)
{
    ui->codeEdit->setReadOnly(lock);
    _sbiLock->setText(lock ? tr("Locked") : tr("Unlocked"));
    _sbiLock->setIcon(lock ? QIcon(":/lock") : QIcon(":/unlock"));
}

/**
 * @private
 * Automatically selects a syntax highlighter according to opened file's suffix.
 */
void MainWindow::setSyntax(const QString& fileSuffix)
{
    QStringList cppFiles;
    cppFiles << "cpp" << "cxx" << "h" << "hpp" << "c";
    QStringList pascalFiles;
    pascalFiles << "pas" << "dpr";
    QStringList sqlFiles;
    sqlFiles << "sql";
    QStringList htmlFiles;
    htmlFiles << "html" << "htm" << "php" << "xml";

    if (cppFiles.indexOf(fileSuffix) != -1) {
        ui->actSyntaxCpp->trigger();
    }
    else if (pascalFiles.indexOf(fileSuffix) != -1) {
        ui->actSyntaxPascal->trigger();
    }
    else if (sqlFiles.indexOf(fileSuffix) != -1) {
        ui->actSyntaxSql->trigger();
    }
    else if (htmlFiles.indexOf(fileSuffix) != -1) {
        ui->actSyntaxHtml->trigger();
    }
    else {
        ui->actSyntaxNone->trigger();
    }
}

/**
 * @private slot
 * Selects a syntax highlighter correspoding to the action triggered.
 */
void MainWindow::setSyntax()
{
    QAction* action = qobject_cast<QAction*>(sender());
    if (action) {
        _sbiSyntax->setDefaultAction(action);
        QMap<QString, QVariant> hiliterInfo = action->data().toMap();
        QSyntaxHighlighter *highlighter = SyntaxHighlighterFactory::create(hiliterInfo["key"].toString());
        ui->codeEdit->setSyntaxHighlighter(highlighter);
        _sbiSyntax->setText(hiliterInfo["text"].toString());
    }
}

/**
 * @private slot
 * Toggles whether the window is shown topmost.
 */
void MainWindow::toggleTopMost(bool topMost)
{
#ifndef Q_OS_WIN32
    Qt::WindowFlags flags = topMost ? windowFlags() | Qt::WindowStaysOnTopHint
        : windowFlags() &~ Qt::WindowStaysOnTopHint;
    setWindowFlags(flags);
    show();
#else
    // On win32 we use native API ::SetWindowPos() instead of the portable code.
    SetWindowPos(winId(), topMost ? HWND_TOPMOST : HWND_NOTOPMOST,
                 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
#endif
}

void MainWindow::toggleToolbar()
{
    ui->toolBar->setVisible(!ui->toolBar->isVisible());
    ui->actToggleToolbar->setChecked(ui->toolBar->isVisible());
}

void MainWindow::toggleStatusbar()
{
    ui->statusBar->setVisible(!ui->statusBar->isVisible());
    ui->actToggleStatusbar->setChecked(ui->statusBar->isVisible());
}

/**
 * @private slot
 * Prompts for a line number to locate in the CodeEditor.
 */
void MainWindow::gotoLine()
{
    const int firstLine = 1;
    const int currentLine = ui->codeEdit->currentLine();
    const int lastLine = ui->codeEdit->blockCount();
    bool ok;
    int line = QInputDialog::getInt(this, tr("Goto Line"),
        QString(tr("Enter Line Number (%1 - %2):")).arg(firstLine).arg(lastLine),
        currentLine, firstLine, lastLine, 1, &ok);
    if (ok) {
        ui->codeEdit->gotoLine(line);
    }
}

/**
 * @private slot
 * Updates the current line-column status.
 */
void MainWindow::codeEditCursorPositionChanged()
{
    int line = ui->codeEdit->textCursor().blockNumber();
    int col = ui->codeEdit->textCursor().columnNumber();
    _sbiColRow->setText(QString(tr("%1  %2")).arg(line).arg(col));
}

/**
 * @private slot
 * Opens the file dropped on ui->codeEdit.
 * @note Keep it unchanged if the file is already opened.
 */
void MainWindow::codeEditFileDropped(const QString& fileName)
{
    if (_fileName != fileName) {
        openFile(fileName);
    }
}

/**
 * @private slot
 * Toggles FullScreen mode.
 */
void MainWindow::toggleFullScreen()
{
    if (!isFullScreen()) {
        showFullScreen();
    }
    else {
        showNormal();
    }
}

void MainWindow::about()
{
    AboutDialog dlgAbout(this);
    dlgAbout.exec();
}
